import { resolve } from "path";

/**
 * 主入口文件
 * Copyright(C) 2018 liumurong
 *
 */

/**
 * 核心功能都是使用CPP实现的，在此只是把addon模块导出即可
 */
let fdb = require('./build/Release/freedatabase');

/**
 * 原生模块导出的链接对象
 */
export let NativeConnectionOptions: ConnectionOptions = fdb.ConnectionOptions;

/**
 * 原生模块导出的任务选项
 */
export let NativeTaskOptions: TaskOptions = fdb.TaskOptions;

/**
 * 数据库连接对象
 */
export interface ConnectionOptions {
    new(): ConnectionOptions,
    setHost(host: string): void;
    setPort(port: number): void;
    setUsername(user: string): void;
    setPassword(pwd: string): void;
    setDbName(dbname: string): void;
}

/**
 * 时间任务对象
 */
export interface TaskOptions {
    new(): TaskOptions;
    setTaskName(taskname: string): void;
    setTaskID(taskid: number): void;
    setParentTaskID(pid: number): void;
    setPlanS(plans: string): void;
    setPlanE(plane: string): void;

    setActualS(actuals: string): void;
    setActualE(actuale: string): void;
    setTaskType(tasktype: number): void;
    setGuid(guid: string): void;
    setTotalPrice(tprice: number): void;

    setDesc(desc: string): void;
    setBActive(bactive: boolean): void;
    setPercent(percent: number): void;
}

/**
 * 模型信息
 */
export interface PModelInfo {
    modelId: number,
    modelName: string
}
/**
 * 包围盒
 */
export interface SimpleBound {
    minX: number,
    minY: number,
    minZ: number,
    maxX: number,
    maxY: number,
    maxZ: number
}

/**
 * 模型树节点
 */
export interface ModelTreeNode {
    nodeName: string,
    nodeGuid: string,
    nodeGuid2: string,
    tileNo: number,
    parentNodeGuid: string,
    nodeBound: SimpleBound,
    mpParent: ModelTreeNode,
    mChildren: ModelTreeNode[]
}

/**
 * 属性键值对
 */
export interface PropertyKeyVal {
    Name: string,
    NominalValue: string
}
/**
 * 属性集合
 */
export interface PropertySet {
    name: string,
    guid: string,
    keyVal: PropertyKeyVal[]
}

/**
 * 构件类型属性
 */
export interface CompTypeAttr {
    name: string,
    guid: string,
    tag: string,
    predefinedType: string,
    proSetVec: PropertySet[]
}

export interface OpeningElem {
    name: string,
    guid: string,
    objectType: string,
    objectPlacement: string,
    layerGuid: string,
    proSetVec: PropertySet[]
}

export interface CompAttr {
    name: string,
    guid: string,
    objectType: string,
    objectPlacement: string,
    layerGuid: string,
    tag: string,
    linkOpenings: OpeningElem[],
    linkCompType: CompTypeAttr,
    proSetVec: PropertySet[]
}

/**
 * 构件信息
 */
export interface CompInfo {
    name: string,
    guid: string
}

/**
 * 构件类型
 */
export interface CompType {
    name: string,
    typeID: number
}

/**
 * 时间任务
 */
export interface Task {
    taskName: string,
    taskID: number,
    parentTaskID: number,
    planS: string,
    planE: string,
    actualS: string,
    actualE: string,
    taskType: number,
    guid: string,
    totalPrice: number,
    desc: string,
    bActive: boolean,
    percent: number
}

/**
 * 楼层信息
 */
export interface Floor {
    floorFDID: number,
    guid: string,
    name: string,
    objectPlacement: string,
    longName: string,
    compositionType: string,
    elevation: string
}





/**
 * xml属性文件入库
 * @param auth 用户ID，用于访问权限控制
 * @param modelname 模型名称
 * @param matrixpath 数据集路径，定位到pmtc一级
 * @param connopts 数据库连接配置
 * @returns void
 */
export async function importPModelXmlFile(auth: string, modelname: string, matrixpath: string, connopts: ConnectionOptions) {
    return new Promise((resolve, reject) => {
        fdb.importPModelXmlFile(auth, modelname, matrixpath, connopts, (err: any) => {
            // 虽然不知道具体原因，但是这样写(使用setImmediate)确实可以提高1000倍的速度
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}

/**
 * 关闭数据库连接
 * @returns void
 */
export async function openDataSource(opts: ConnectionOptions) {
    return new Promise((resolve, reject) => {
        fdb.openDataSource(opts, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}

/**
 * 关闭数据库连接
 * @returns void
 */
export async function closeDataSource() {
    return new Promise((resolve, reject) => {
        fdb.closeDataSource((err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        })
    });
}
/**
 * 查询模型属性信息
 * 并未按照用户ID进行检索
 * @returns PModelInfo[]  模型信息集合
 */
export async function queryPModelInfo(): Promise<PModelInfo[]> {
    let infos = await new Promise<PModelInfo[]>((resolve, reject) => {
        fdb.queryPModelInfo((err: any, arr: PModelInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(arr);
            });
        });
    });
    return infos;
}

/**
 * 分页查询模型属性信息
 * @param pagenumber 页码
 * @param pagecount 每页条目个数
 * @returns void
 */
export async function queryPModelInfoPage(pagenumber: number, pagecount: number): Promise<{ total: number, infos: PModelInfo[] }> {
    let infos = await new Promise<{ total: number, infos: PModelInfo[] }>((resolve, reject) => {
        fdb.queryPModelInfoPage(pagenumber, pagecount, (err: any, total: number, arr: PModelInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve({
                    total: total,
                    infos: arr
                });
            });
        });
    });
    return infos;
}
/**
 * 检测模型是否存在
 * @param modelname 模型名称
 * @returns number 模型ID
 */
export async function existsPModel(modelname: string): Promise<number> {
    return new Promise<number>((resolve, reject) => {
        fdb.existsPModel(modelname, (err: any, modelId: number) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(modelId);
            });
        });
    });
}

/**
 * 验证是否有权限访问此模型
 * @param auth 用户ID
 * @param modelId 模型ID
 * @returns boolean 是否有访问权限
 */
export async function hasPModelPermission(auth: string, modelId: number): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
        fdb.hasPModelPermission(auth, modelId, (err: any, accessed: boolean) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(accessed);
            });
        });
    });
}

/**
 * 添加用户对某模型的访问权限
 * @param auth 用户ID
 * @param modelId 模型ID
 * @returns boolean 授权是否成功
 */
export async function addPModelPermission(auth: string, modelId: number): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
        fdb.addPModelPermission(auth, modelId, (err: any, accessed: boolean) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(accessed);
            });
        });
    });
}
/**
 * 删除用户对某模型的访问权限
 * @param auth 用户ID
 * @param modelId 模型ID
 * @returns void
 */
export async function removePModelPermission(auth: string, modelId: number) {
    return new Promise((resolve, reject) => {
        fdb.addPModelPermission(auth, modelId, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}

/**
 * 查询模型结构树根节点
 * @param modelId 模型ID
 * @returns ModelTreeNode 根节点
 */
export async function queryPModelRootTree(modelId: number): Promise<ModelTreeNode> {
    return new Promise<ModelTreeNode>((resolve, reject) => {
        fdb.queryPModelRootTree(modelId, (err: any, rootnode: ModelTreeNode) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(rootnode);
            });
        });
    });
}
/**
 * 查询树子节点---分页
 * @param modelId 模型ID
 * @param pguid 父节点GUID
 * @param pagenumber 页码
 * @param pagecount 每页记录个数
 * @returns ModelTreeNode[] 子节点数组
 */
export async function queryPModelChildTreePage(modelId: number, pguid: string, pagenumber: number, pagecount: number): Promise<ModelTreeNode[]> {
    return new Promise<ModelTreeNode[]>((resolve, reject) => {
        fdb.queryPModelChildTreePage(modelId, pguid, pagenumber, pagecount, (err: any, cnodes: ModelTreeNode[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(cnodes);
            });
        });
    });
}

/**
 * 直接根据Guid查询某一级子节点
 * @param modelId 模型ID
 * @param guid 节点GUID
 * @returns ModelTreeNode 树节点
 */
export async function queryPModelTreeByGuid(modelId: number, guid: string): Promise<ModelTreeNode> {
    return new Promise<ModelTreeNode>((resolve, reject) => {
        fdb.queryPModelTreeByGuid(modelId, guid, (err: any, n: ModelTreeNode) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(n);
            });
        });
    });
}

/**
 * 直接根据Guid查询某父节点
 * @param modelId 模型ID
 * @param guid 节点GUID
 * @returns ModelTreeNode 节点
 */
export async function queryPModelParentTreeByGuid(modelId: number, guid: string): Promise<ModelTreeNode> {
    return new Promise<ModelTreeNode>((resolve, reject) => {
        fdb.queryPModelParentTreeByGuid(modelId, guid, (err: any, n: ModelTreeNode) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(n);
            });
        });
    });
}

/**
 * 查询树子节点
 * @param modelId 模型ID
 * @param pguid 父节点GUID
 * @returns ModelTreeNode[] 子节点数组
 */
export async function queryPModelChildTree(modelId: number, pguid: string): Promise<ModelTreeNode[]> {
    return new Promise<ModelTreeNode[]>((resolve, reject) => {
        let tileno = 0; // tileno不再需要，此处仅用于占位
        fdb.queryPModelChildTree(modelId, pguid, tileno, (err: any, cnodes: ModelTreeNode[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(cnodes);
            });
        });
    });
}

/**
 * 查询模型部件属性
 * @param modelId 模型ID
 * @param guid 部件ID
 * @returns CompAttr 模型部件
 */
export async function queryPModelCompAttr(modelId: number, guid: string): Promise<CompAttr> {
    return new Promise<CompAttr>((resolve, reject) => {
        fdb.queryPModelCompAttr(modelId, guid, (err: any, attr: CompAttr) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(attr);
            });
        });
    });
}
/**
 * 条件查询属性
 * @param modelId 模型ID
 * @param propKey 属性Key
 * @param propVal 属性值
 * @returns CompInfo[] 属性信息集合
 */
export async function queryPModelCompByProperty(modelId: number, propKey: string, propVal: string): Promise<CompInfo[]> {
    return new Promise<CompInfo[]>((resolve, reject) => {
        fdb.queryPModelCompByProperty(modelId, propKey, propVal, (err: any, infos: CompInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(infos);
            });
        });
    });
}

/**
 * 分页-条件查询属性
 * @param modelId 模型ID
 * @param propKey 属性Key
 * @param propVal 属性值
 * @param pagenumber 页码
 * @param pagecount 每页记录个数
 */
export async function queryPModelCompByPropertyPage(modelId: number, propKey: string, propVal: string, pagenumber: number, pagecount: number): Promise<{ total: number, infos: CompInfo[] }> {
    return new Promise<{ total: number, infos: CompInfo[] }>((resolve, reject) => {
        fdb.queryPModelCompByPropertyPage(modelId, propKey, propVal, pagenumber, pagecount, (err: any, total: number, infos: CompInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve({
                    total: total,
                    infos: infos
                });
            });
        });
    });
}
/**
 * 查询所有构件类型
 * @param modelId 模型ID
 * @returns CompType[] 构件类型
 */
export async function queryPModelCompType(modelId: number): Promise<CompType[]> {
    return new Promise<CompType[]>((resolve, reject) => {
        fdb.queryPModelCompType(modelId, (err: any, types: CompType[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(types);
            });
        });
    });
}

/**
 * 根据构件类型ID查询构件信息
 * @param modelId 模型ID
 * @param typeId 构件类型ID
 */
export async function queryPModelCompByType(modelId: number, typeId: number): Promise<CompInfo[]> {
    return new Promise<CompInfo[]>((resolve, reject) => {
        fdb.queryPModelCompByType(modelId, typeId, (err: any, infos: CompInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(infos);
            });
        });
    });
}
/**
 * 分页-根据构件类型ID查询构件信息
 * @param modelId 模型ID 
 * @param typeId 类型ID
 * @param pagenumber 页码
 * @param pagecount 每页记录个数
 */
export async function queryPModelCompByTypePage(modelId: number, typeId: number, pagenumber: number, pagecount: number): Promise<{ total: number, infos: CompInfo[] }> {
    return new Promise<{ total: number, infos: CompInfo[] }>((resolve, reject) => {
        fdb.queryPModelCompByTypePage(modelId, typeId, pagenumber, pagecount, (err: any, total: number, infos: CompInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve({
                    total: total,
                    infos: infos
                });
            });
        });
    });
}
/**
 * 根据构件GUID更新构件属性
 * @param modelId 模型ID
 * @param guid 构件GUID
 * @param propKey 属性Key
 * @param propVal 属性值
 * @returns void
 */
export async function updatePModelProperty(modelId: number, guid: string, propKey: string, propVal: string) {
    return new Promise((resolve, reject) => {
        fdb.updatePModelProperty(modelId, guid, propKey, propVal, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}


/**
 * 插入构件属性
 * @param modelId 模型ID
 * @param guid 构件GUID
 * @param setid 属性集ID
 * @param propKey 属性Key
 * @param propVal 属性值
 * @returns void
 */
export async function insertPModelProperty(modelId: number, guid: string, setid: string, propKey: string, propVal: string) {
    return new Promise((resolve, reject) => {
        fdb.insertPModelProperty(modelId, guid, setid, propKey, propVal, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}
/**
 * 删除属性
 * @param modelId 模型ID
 * @param guid 组件ID
 * @param setid 属性集合ID
 * @param propKey 属性键
 */
export async function deletePModelProperty(modelId: number, guid: string, setid: string, propKey: string) {
    return new Promise((resolve, reject) => {
        fdb.deletePModelProperty(modelId, guid, setid, propKey, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}

/**
 * 根据Tag值查询模型属性
 * @param modelId 模型ID
 * @param tagid TagID
 * @returns CompAttr 构件属性
 */
export async function queryPModelCompAttrByTag(modelId: number, tagid: string): Promise<CompAttr> {
    return new Promise<CompAttr>((resolve, reject) => {
        fdb.queryPModelCompAttrByTag(modelId, tagid, (err: any, attr: CompAttr) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(attr);
            });
        });
    });
}

/**
 * 查询楼层信息
 * @param modelId 模型ID
 */
export async function queryPModelFloors(modelId: number): Promise<Floor[]> {
    return new Promise<Floor[]>((resolve, reject) => {
        fdb.queryPModelFloors(modelId, (err: any, floors: Floor[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(floors);
            });
        });
    });
}
/**
 * 查询楼层构件
 * @param modelId 模型ID
 * @param floorId 楼层ID
 * @param pagenumber 页码
 * @param pagecount 每页记录个数
 */
export async function queryPModelCompByFloorPage(modelId: number, floorId: number, pagenumber: number, pagecount: number): Promise<CompInfo[]> {
    return new Promise<CompInfo[]>((resolve, reject) => {
        fdb.queryPModelCompByFloorPage(modelId, floorId, pagenumber, pagecount, (err: any, comp: CompInfo[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(comp);
            });
        });
    });
}


/**
 * 插入一条新的时间任务
 * @param modelId 模型ID
 * @param opts 时间任务参数
 * @returns void
 */
export async function insertPModelTask(modelId: number, opts: TaskOptions) {
    return new Promise((resolve, reject) => {
        fdb.insertPModelTask(modelId, opts, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}

/**
 * 删除时间任务
 * @param modelId 模型ID
 * @param taskId 任务ID
 * @returns void
 */
export async function removePModelTask(modelId: number, taskId: number) {
    return new Promise((resolve, reject) => {
        fdb.removePModelTask(modelId, taskId, (err: any) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    });
}
/**
 * 分页查询时间任务
 * @param modelId 模型ID
 * @param pagenumber 页码
 * @param pagecount 每页记录条数
 */
export async function queryPModelTaskPage(modelId: number, pagenumber: number, pagecount: number): Promise<{ total: number, tasks: Task[] }> {
    return new Promise<{ total: number, tasks: Task[] }>((resolve, reject) => {
        fdb.queryPModelTaskPage(modelId, pagenumber, pagecount, (err: any, total: number, tasks: Task[]) => {
            setImmediate(() => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve({
                    total: total,
                    tasks: tasks
                });
            });
        });
    });
}




